#pragma once

#include <QtCore/QUuid>
#include <QtWidgets/QGraphicsObject>

#include "QtConnection.hpp"
#include <QtCore/QObject>
#include <QtWidgets/QWidget>

class QGraphicsProxyWidget;

namespace Qt
{
	class QtNode;
	class NodeState;
	class NodeGeometry;
	class QtNodeGraphicsObject;
	class QtNodeDataModel;
	class QtFlowScene;


	/// Class to allow for custom painting
	class NODE_EDITOR_PUBLIC QtNodePainterDelegate
	{

	public:

		virtual
			~QtNodePainterDelegate() = default;

		virtual void
			paint(QPainter* painter,
				NodeGeometry const& geom,
				QtNodeDataModel const * model) = 0;
	};

	class NODE_EDITOR_PUBLIC HotkeyButton
	{
	public:

		enum HotkeyState
		{
			defaultState = 0,
			checkedState = 1,
			hoverState = 2,
			clickState = 3,
			lastCheckedState = 4
		};
		
		enum HotkeyMode
		{
			clickMode = 0,
			checkedMode = 1,
			label = 2
		};
		HotkeyButton() {}

		~HotkeyButton() {}

		void setTransform(QPointF ori, unsigned int x, unsigned int y);

		bool isPointInButton(const QPointF& point);
		bool isChecked();
		
		void setState(HotkeyState state);
		void setUserPolicy(std::function<bool()> policy);

		void setChecked(bool c) 
		{
			mDefaultChecked = c;
			if (mMode == mDefaultChecked)
			{
				if (mDefaultChecked)
					mState = checkedState;
				else
					mState = defaultState;
			}
		}

		bool mouseHover(const QPointF& point);

		bool mouseClick(const QPointF& point);

		void leaveWidget();

		void setMode(HotkeyMode mode) { mMode = mode; }

		bool mouseRelease(const QPointF& point);

		HotkeyState getState() { return mState; }

		QPointF getOrigin() { return mOrigin; }
		QSize getSize() { return mSize; };
	
		const char* getIcon();

		void setIconsPath(const char* defaultIcon, const char* checkedIcon, const char* hoverIcon, const char* clickIcon);

		void setSize(unsigned int x, unsigned int y);

	public:

		float scaleX = 1;

	private:
		bool mDefaultChecked = false;

		QPointF mOrigin = QPointF(0,0);		

		QSize mSize = QSize(0,0);

		std::string mDefaultIcon = ":nodeSimUnChecked.png";
		std::string mCheckedIcon = ":nodeSim.png";
		std::string mHoverIcon = ":nodeReset.png";
		std::string mClickIcon = ":nodeSim.png";

		std::function<bool()> mCheckedFunc;

		HotkeyState mState = defaultState;
		HotkeyMode mMode = checkedMode;
	};

	class QtNodePainter
	{
	public:

		QtNodePainter();


	public:

		static
			void
			paint(QPainter* painter,
				QtNode& node,
				QtFlowScene const& scene);

		static
			void
			drawNodeRect(QPainter* painter,
				NodeGeometry const& geom,
				QtNodeDataModel const* model,
				QtNodeGraphicsObject const & graphicsObject);

		static
			void
			drawHotKeys(QPainter* painter,
				NodeGeometry const& geom,
				QtNodeDataModel const* model,
				QtNodeGraphicsObject const & graphicsObject);

		static
			void
			drawModelName(QPainter* painter,
				NodeGeometry const& geom,
				NodeState const& state,
				QtNodeDataModel const * model);

		static
			void
			drawEntryLabels(QPainter* painter,
				NodeGeometry const& geom,
				NodeState const& state,
				QtNodeDataModel const * model);

		static
			void
			drawConnectionPoints(QPainter* painter,
				NodeGeometry const& geom,
				NodeState const& state,
				QtNodeDataModel const * model,
				QtFlowScene const & scene);

		static
			void
			drawFilledConnectionPoints(QPainter* painter,
				NodeGeometry const& geom,
				NodeState const& state,
				QtNodeDataModel const * model);

		static
			void
			drawResizeRect(QPainter* painter,
				NodeGeometry const& geom,
				QtNodeDataModel const * model);

		static
			void
			drawValidationRect(QPainter * painter,
				NodeGeometry const & geom,
				QtNodeDataModel const * model,
				QtNodeGraphicsObject const & graphicsObject);

	};

	/// Class reacts on GUI events, mouse clicks and
	/// forwards painting operation.
	class QtNodeGraphicsObject : public QGraphicsObject
	{
		Q_OBJECT

	public:
		QtNodeGraphicsObject(QtFlowScene &scene,
			QtNode& node);

		virtual
			~QtNodeGraphicsObject();

		QtNode&
			node();

		QtNode const&
			node() const;

		QRectF
			boundingRect() const override;

		void
			setGeometryChanged();

		/// Visits all attached connections and corrects
		/// their corresponding end points.
		void
			moveConnections() const;

		enum { Type = UserType + 1 };

		int	type() const override { return Type; }

		void
			lock(bool locked);


	protected:
		void
			paint(QPainter*                       painter,
				QStyleOptionGraphicsItem const* option,
				QWidget*                        widget = 0) override;

		QVariant
			itemChange(GraphicsItemChange change, const QVariant &value) override;

		void
			mousePressEvent(QGraphicsSceneMouseEvent* event) override;

		void
			mouseMoveEvent(QGraphicsSceneMouseEvent* event) override;

		void
			mouseReleaseEvent(QGraphicsSceneMouseEvent* event) override;

		void
			hoverEnterEvent(QGraphicsSceneHoverEvent* event) override;

		void
			hoverLeaveEvent(QGraphicsSceneHoverEvent* event) override;

		void
			hoverMoveEvent(QGraphicsSceneHoverEvent *) override;

// 		void
// 			mouseDoubleClickEvent(QGraphicsSceneMouseEvent* event) override;

		/**
		 * To emit the nodeContextMenu signal, use it to create a custom context menu in the subclass
		 */
		void contextMenuEvent(QGraphicsSceneContextMenuEvent* event) override;

		void timerEvent(QTimerEvent * event )override;

		void hideTipsAndTimer();


		
	private:
		void
			embedQWidget();

	private Q_SLOTS:
		void nodeSelection();
		
		void redraw() 
		{
			this->update();
		};

	private:

		QtFlowScene & _scene;

		QtNode& _node;

		QPainter* _defaultPainter;

		bool _locked;

		int _pressCounter = 0;

		int HelpTimerID = -1;
		int PortTimerID = -1;



		// either nullptr or owned by parent QGraphicsItem
		QGraphicsProxyWidget * _proxyWidget;
	};
}
